package com.wswy.wzcx.module

import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.che.libcommon.api.ApiOptionalResultObserver
import com.che.libcommon.api.BaseResult
import com.che.libcommon.utils.AssetUtils
import com.che.libcommon.utils.optional.Optional
import com.wswy.wzcx.BuildConfig
import com.wswy.wzcx.utils.RxUtils
import com.wswy.wzcx.utils.Tools
import com.wswy.wzcx.utils.toJson
import io.reactivex.Observable
import io.reactivex.Single
import java.util.concurrent.TimeUnit

abstract class AbsCacheLoader<T>(private val context: Context, private val assetsName: String?=null) {


    companion object {
        private const val TAG = "AbsCacheLoader"

    }

    @Volatile private var currentData:T?=null //保存当前数据，尽量避免减少刷新

    @SuppressLint("CheckResult")
    fun loadOnce(block: ((Optional<out T?>) -> Unit)?){

        loadFromApi().timeout(5L,TimeUnit.SECONDS)
                .subscribe(object :ApiOptionalResultObserver<T?>(){
                    override fun onApiResult(t: T?) {
                        block?.invoke(Optional.ofNullable(t))
                    }

                    override fun onApiError(result: BaseResult<*>?) {


                        loadFromApiCache().firstOrError().subscribe { t1, t2 ->


                            t2?.run {

                                block?.invoke(Optional.absent())

                            }?:kotlin.run {
                                block?.invoke(Optional.ofNullable(t1?.orNull()))
                            }

                        }

                    }

                })


//        Single.concat(loadFromApi().timeout(3L,TimeUnit.SECONDS).doOnError {
//
//            it?.printStackTrace()
//
//        }.doAfterSuccess {
//
//            Log.e(TAG, " -->once success  "+it.orNull());
//
//        },loadFromApiCache().firstOrError())
//                .compose(RxUtils.io2main())
//                .filter { it.isPresent }
//                .timeout(3L,TimeUnit.SECONDS)
//                .first(Optional.absent())
//                .subscribe({
//                    block?.invoke(it)
//                },{
//                    block?.invoke(Optional.absent())
//                })

    }

    @SuppressLint("CheckResult")
    fun loader(block: ((Optional<out T?>) -> Unit)?) {
        //如果
        Observable.concat(loadFromApiCache(),loadFromAssets()).compose(RxUtils.io2main())
                .filter { it.isPresent }
                .firstOrError().doFinally {
                    //无论成功是否成功，都从网络加载一次
                    updateFromApi(block).subscribe { _, err ->


                        err?.printStackTrace()

                    }

                }.subscribe { t1, t2 ->

                    if (t2 == null){

                        //比较数据
                        if (compareData()){

                            //与老数据不一样 刷新
                            if (currentData == null || currentData != t1){
                                currentData = t1?.orNull()

                                block?.invoke(t1)
                            }

                        }else{
                            block?.invoke(t1)
                        }

                    }else{
                        t2.printStackTrace()
                    }

                }

    }



    private fun loadFromAssets(): Observable<Optional<T?>> {

        return Observable.create<Optional<T?>> {
            try {
                if (TextUtils.isEmpty(assetsName)){
                    it.onComplete()
                }else {
                    val data = AssetUtils.read2String(context, assetsName)
                    if (TextUtils.isEmpty(data)) {
                        it.onComplete()
                    } else {
                        it.onNext(Optional.ofNullable(convert(data!!)))

                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
                it.onComplete()
            }
        }
    }

    private fun loadFromApiCache(): Observable<Optional<T?>> {

        return  Observable.create<Optional<T?>> {
            try {
                val data = Tools.getApiCache().getString(getKey())

                if (BuildConfig.DEBUG){
                    Log.e(TAG, " -->loader cache  ${Thread.currentThread()} ");
                    Log.e(TAG, " -->loader cache ${getKey()} --> $data")
                }


                if (TextUtils.isEmpty(data)) {
                    //没有缓存，从下一个读取
                    it.onComplete()
                } else {
                    //如果缓存读取成功，则不要读取下一个了
                    it.onNext(Optional.ofNullable(convert(data)))
                }
            } catch (e: Exception) {
                Tools.getApiCache().remove(getKey())
                it.onComplete()
            }
        }

    }


    private fun updateFromApi(block: ((Optional<out T?>) -> Unit)?): Single<Optional<T?>> {
        return loadFromApi().doAfterSuccess {
            val data = it.orNull()?.apply {
                saveCache(this)
            }

            //空数据，删除
            if (!it.isPresent){
                Tools.getApiCache().remove(getKey())
            }

            //此处 首页模块缓存比较特殊，仍然会刷新两次，是因为有改变对象的tag属性
            //比较数据
            if (compareData()){
                if(currentData == null || currentData != data){
                    currentData = data
                    block?.invoke(it)
                }
            }else{
                block?.invoke(it)
            }
        }
    }

    protected abstract fun loadFromApi(): Single<Optional<T?>>

    protected abstract fun convert(json: String): T?

    protected abstract fun getKey(): String

    protected open fun compareData():Boolean = true

    private fun saveCache(data: T) {
        if (BuildConfig.DEBUG){
            Log.e(TAG, "loader save  --> ${getKey()}    ${toJson(data)}");
        }

        Tools.getApiCache().put(getKey(), toJson(data),TimeUnit.MINUTES.toSeconds(30).toInt())
    }

}
